﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using RuYiAdmin.Net.Common.Global;
using RuYiAdmin.Net.Common.Utility;
using RuYiAdmin.Net.Entity.BusinessEnum;
using RuYiAdmin.Net.Service.BusinessService.Redis;
using RuYiAdmin.Net.WebApi.AppCode.Base;
using RuYiAdmin.Net.WebApi.AppCode.Filter;
using RuYiAdmin.Net.WebApi.AppCode.JWT;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace RuYiAdmin.Net.WebApi.Controllers.Jwt
{
    /// <summary>
    /// JWT接口认证控制器
    /// </summary>
    [ApiController]
    [Route(GlobalContext.RouteTemplate)]
    public class AuthenticateController : ControllerBase
    {
        private readonly IRedisService redisService;

        /// <summary>
        /// 构造函数
        /// </summary>
        public AuthenticateController(IRedisService redisService)
        {
            this.redisService = redisService;
        }

        /// <summary>
        /// 获取盐
        /// </summary>
        /// <returns>盐</returns>
        [HttpGet]
        [AllowAnonymous]
        //[Log(OperationType.QueryList)]
        public async Task<IActionResult> Get(String userName)
        {
            if (String.IsNullOrEmpty(userName))
            {
                return BadRequest("user name can not be null");
            }

            if (userName.Equals(GlobalContext.JwtSettings.DefaultUser))
            {
                var salt = Guid.NewGuid();
                var encrytStr = Md5Util.Encrypt(GlobalContext.JwtSettings.DefaultPassword, salt);
                await redisService.SetAsync(salt.ToString(), encrytStr, GlobalContext.JwtSettings.SaltExpiration);
                var actionResult = new RuYiAdmin.Net.Entity.CoreEntity.ActionResult()
                {
                    HttpStatusCode = HttpStatusCode.OK,
                    Object = salt,
                    Message = new String("OK")
                };
                return Ok(actionResult);
            }

            return NoContent();
        }

        /// <summary>
        /// JWT身份认证接口
        /// </summary>
        /// <param name="jwtAuthentication">身份信息</param>
        /// <returns>token信息</returns>
        [HttpPost]
        [AllowAnonymous]
        public IActionResult Post([FromBody] JwtAuthentication jwtAuthentication)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState.ValidationState);
            }

            var encrytStr = String.Empty;

            if (redisService.Exists(new string[] { jwtAuthentication.Salt }) > 0)
            {
                encrytStr = redisService.Get(jwtAuthentication.Salt);
            }

            if (String.IsNullOrEmpty(encrytStr))
            {
                return BadRequest("salt is not validated");
            }

            if (jwtAuthentication.UserName.Equals(GlobalContext.JwtSettings.DefaultUser) && jwtAuthentication.Password.Equals(encrytStr))
            {
                redisService.Delete(new string[] { jwtAuthentication.Salt });
                var token = JwtAuthentication.GetJwtSecurityToken(jwtAuthentication.UserName);
                //设置RefreshToken有效期
                this.redisService.Set(token.Id, token.Id, 12 * 3 * GlobalContext.JwtSettings.TokenExpiration * 60);
                var actionResult = new RuYiAdmin.Net.Entity.CoreEntity.ActionResult()
                {
                    HttpStatusCode = HttpStatusCode.OK,
                    Object = new { AccessToken = new JwtSecurityTokenHandler().WriteToken(token), RefreshToken = token.Id },
                    Message = "OK,expiration:" + token.ValidTo.ToLocalTime()
                };
                return Ok(actionResult);
            }

            return NotFound();
        }

        /// <summary>
        /// 刷新口令
        /// </summary>
        /// <returns>ActionResult</returns>
        [HttpGet]
        [AllowAnonymous]
        public IActionResult RefreshToken()
        {
            String accessToken = this.HttpContext.Request.Headers["Authorization"];
            String refreshToken = this.HttpContext.Request.Headers["RefreshToken"];
            var jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(accessToken);
            if (jwtToken.Id.Equals(refreshToken))
            {
                var rtValue = this.redisService.Get(refreshToken);
                if (!String.IsNullOrEmpty(rtValue) && rtValue.Equals(refreshToken))
                {
                    var token = JwtAuthentication.GetJwtSecurityToken(GlobalContext.JwtSettings.DefaultUser);
                    var actionResult = new RuYiAdmin.Net.Entity.CoreEntity.ActionResult()
                    {
                        HttpStatusCode = HttpStatusCode.OK,
                        Object = new { AccessToken = new JwtSecurityTokenHandler().WriteToken(token), RefreshToken = token.Id },
                        Message = "OK,expiration:" + token.ValidTo.ToLocalTime()
                    };
                    return Ok(actionResult);
                }
            }
            return Forbid();
        }
    }
}
